#pragma once

#include <vector>
#include <unordered_map>
#include <unistd.h>

#include "worker.h"
#include "service.h"
#include "socket_worker.h"
#include "conn.h"

/**
 * sunnet 类, 统筹管理整个系统.
 * It is an orchestrator.
 *
 * 1. 管理服务类, 有 unordered_map<uint32_t, shared_ptr<service>> services,
 * 还有 newservice, killservice, get_service
 * 2. 一个全局队列, 表示哪些服务有消息待处理, queue<shared_ptr<service>> global_queue
 * 还有 send, push_global_queue, pop_global_queue
 * 3. 启动工作线程, start_worker, start_socket_worker
 * 4. 其他, 如让线程进入休眠, 唤醒线程, 封装网络连接(conn), 等系统所必要的接口.
 */

/**
 * 关于c++11 成员变量初始化的问题.
 * 1. 基础成员变量的初始化是未定义的, 但是可以类内初始化, 比如 int a = 1;
 * 2. 指针是未定义的, 需要显示初始化.
 * 3. STL 对象会调用自己的构造函数, 容器一般初始化为 空, 故, 一般不需要显示初始化它.
 * 4. 静态成员变量, 未定义, 且必须显示初始化.
 * 5. 类类型变量, 参考 STL 对象.
 */

class sunnet
{
public:
    // 单例
    static sunnet *inst;

public:
    // 服务列表
    unordered_map<uint32_t, shared_ptr<service>> services;
    pthread_rwlock_t services_lock;
    uint32_t maxid = 0;

private:
    // 线程
    int worker_num = 2;
    vector<worker *> workers;
    vector<thread *> worker_threads;

private:
    // 网络线程
    socket_worker *soc_worker;
    thread *soc_thread;

private:
    // 充分利用 CPU
    // 定义全局服务队列
    queue<shared_ptr<service>> global_queue; // 全局队列
    int global_queue_len = 0;                // 队列长度
    pthread_spinlock_t global_queue_lock;    // 自旋锁

private:
    // 休眠和唤醒
    pthread_mutex_t sleep_mutex_lock;
    pthread_cond_t sleep_cond;
    int sleep_count = 0;

private:
    // conn list
    unordered_map<uint32_t, shared_ptr<conn>> conns;
    pthread_rwlock_t conns_lock;

public:
    // 构造函数
    sunnet();
    // 初始化
    void start();
    // 等待运行
    void wait();

public:
    // 增删服务
    uint32_t newservice(shared_ptr<string> type);
    void killservice(uint32_t id); // 服务自己调用

public:
    // 发送消息
    void send(uint32_t id, shared_ptr<base_msg> msg);
    // 操作全局队列
    void push_global_queue(shared_ptr<service> srv);
    shared_ptr<service> pop_global_queue();

    // 测试
    shared_ptr<base_msg> make_msg(uint32_t source, char *buff, size_t size);

public:
    // 唤醒工作线程
    void check_and_weakup();
    // 让工作线程等待
    void worker_wait();

public:
    // 网络操作接口
    int Listen(uint32_t port, uint32_t serviceid);
    void close_conn(uint32_t fd);

public:
    //
    void modify_event(int fd, bool epollOut);
    //
    // void on_socket_close(uint32_t id);

public:
    // conns curd
    int add_conn(int fd, uint32_t serviceid, conn_type type); // 每一个连接对应一个 conn 对象
    shared_ptr<conn> get_conn(int fd);
    bool remove_conn(int fd);

private:
    // 开启 worker 线程
    void start_worker();

private:
    // 开启 socket 线程
    void start_socket_worker();

private:
    // 获取服务
    shared_ptr<service> get_service(uint32_t id);
};